package com.ygqh.baby.config;

import com.ygqh.baby.redis.RedisDao;
import com.ygqh.baby.shiro.credentials.MyCredentialsMatcher;
import com.ygqh.baby.shiro.filter.JsonFormAuthenticationFilter;
import com.ygqh.baby.shiro.realm.YgUserRealm;
import com.ygqh.baby.shiro.session.RedisSessionDAO;
import com.ygqh.baby.shiro.session.SimpleSessionFactory;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.Map;

@Configuration
public class ShiroConfig {

    @Autowired
    private YgUserRealm ygUserRealm;
    
    private final static String KEY_PREFIX = "shiro_chat_redis_session:";
    
    @Bean
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    public YgUserRealm ygUserRealm(){
    	ygUserRealm.setCredentialsMatcher(credentialsMatcher());
    	ygUserRealm.setCachingEnabled(true);
    	ygUserRealm.setAuthenticationCachingEnabled(true);
    	ygUserRealm.setAuthenticationCacheName("authenticationCache");
    	ygUserRealm.setAuthorizationCachingEnabled(true);
    	ygUserRealm.setAuthorizationCacheName("authorizationCache");
        return ygUserRealm;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager(DefaultWebSessionManager sessionManager){
    	DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(ygUserRealm());
		securityManager.setRememberMeManager(rememberMeManager());
		securityManager.setSessionManager(sessionManager);
		return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
    	ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
		shiroFilterFactoryBean.setUnauthorizedUrl("/chat/admin/unauthorized.do?callback=fn");
		Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
		filters.put("authc", jsonFormAuthenticationFilter());
		Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
		filterChainDefinitionMap.put("/chat/adminuser/*", "anon");
		filterChainDefinitionMap.put("/chat/file/*", "anon");
		filterChainDefinitionMap.put("/chat/admin/ygUserLogin.do", "anon");
		filterChainDefinitionMap.put("/chat/admin/ygUserLogout.do", "anon");
		filterChainDefinitionMap.put("/chat/admin/customerUserLogin.do", "anon");
		filterChainDefinitionMap.put("/chat/admin/customerUserLogout.do", "anon");
		filterChainDefinitionMap.put("/chat/admin/appCustomerUserLogin.do", "anon");
		filterChainDefinitionMap.put("/chat/admin/appCustomerUserLogout.do", "anon");		
		filterChainDefinitionMap.put("/chat/admin/unauthorized.do", "anon");
		filterChainDefinitionMap.put("/chat/user/*", "authc, roles[ygUser]");
		filterChainDefinitionMap.put("/chat/report/*", "anon");
		filterChainDefinitionMap.put("/chat/customer/*", "authc, roles[customerUser]");
		filterChainDefinitionMap.put("/**", "authc");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
    }

	public JsonFormAuthenticationFilter jsonFormAuthenticationFilter() {
		JsonFormAuthenticationFilter filter = new JsonFormAuthenticationFilter();
		filter.setUsernameParam("username");
		filter.setPasswordParam("password");
		filter.setRememberMeParam("rememberMe");
		return filter;
	}

    public MyCredentialsMatcher credentialsMatcher(){
    	MyCredentialsMatcher credentialsMatcher = new MyCredentialsMatcher();
    	credentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
    	credentialsMatcher.setHashIterations(2);//散列的次数，比如散列两次，相当于 md5(md5(""));
    	credentialsMatcher.setStoredCredentialsHexEncoded(true);
        return credentialsMatcher;
    }

    public HashedCredentialsMatcher hashedCredentialsMatcher(){
    	HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    	hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
    	hashedCredentialsMatcher.setHashIterations(2);//散列的次数，比如散列两次，相当于 md5(md5(""));
    	hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }

	public CookieRememberMeManager rememberMeManager() {
		CookieRememberMeManager manager = new CookieRememberMeManager();
		manager.setCookie(rememberMeCookie());
		return manager;
	}

	public SimpleCookie rememberMeCookie() {
		SimpleCookie cookie = new SimpleCookie("rememberMe");
		cookie.setMaxAge(25920000);
		return cookie;
	}

    /**
     * RedisSessionDAO shiro sessionDao层的实现 通过redis
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public RedisSessionDAO redisSessionDAO(RedisDao redisDao) {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setKeyPrefix(KEY_PREFIX);
        redisSessionDAO.setRedisDao(redisDao);
        redisSessionDAO.setExpire(25920000);
        return redisSessionDAO;
    }

    /**
     * shiro session的管理
     */
    @Bean
    public DefaultWebSessionManager sessionManager(RedisSessionDAO sessionDAO) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(sessionDAO);
        sessionManager.setSessionFactory(new SimpleSessionFactory());
        sessionManager.setGlobalSessionTimeout(36000000);
		sessionManager.setDeleteInvalidSessions(true);
		sessionManager.setSessionValidationSchedulerEnabled(true);
        return sessionManager;
    }

}
